package org.sbbs.tool;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.Validation;
import javax.validation.ValidatorFactory;

import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.location.BeanConstraintLocation;
import org.hibernate.validator.internal.metadata.location.MethodConstraintLocation;

public class ValidatorUtil {
    BeanMetaData mata;

    String fieldName;

    String methodName;

    String javaType;

    List<String> classVL = new ArrayList<String>();

    List<String> otherVL = new ArrayList<String>();

    public ValidatorUtil( String entityFullName )
        throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        // factory.
        BeanMetaDataManager bm = new BeanMetaDataManager( new ConstraintHelper() );

        // Class.forName( "DemoEntity").getClass();
        mata = bm.getBeanMetaData( Class.forName( entityFullName ).newInstance().getClass() );

        /*
         * BeanMetaData mata = bm.getBeanMetaData( DemoEntity.class );
         */

        // Set<MetaConstraint> dcs = mata.getDirectMetaConstraints();
    }

    /**
     * @param fieldName
     * @return
     */
    public String getFormValidationString( String fieldName ) {
        boolean typeValidation = false;
        this.fieldName = fieldName;
        this.methodName = this.getFieldMethodName( fieldName );

        Set<MetaConstraint> dcs = mata.getDirectMetaConstraints();

        for ( Iterator iterator = dcs.iterator(); iterator.hasNext(); ) {
            MetaConstraint mc = (MetaConstraint) iterator.next();
            String fn = mc.getLocation().getMember().getName();
            if ( fn.equals( this.fieldName ) || fn.equals( this.methodName ) ) {

                if ( !typeValidation ) {
                    String tv = this.getFieldTypeClassValidation( mc );
                    if ( tv != null )
                        classVL.add( tv );
                    typeValidation = true;
                }

                this.getFieldValidation( mc );
                // this.getFieldOtherValidation( mc );

                /*
                 * if ( cv != null ) classVL.add( cv ); if ( ov != null ) otherVL.add( ov );
                 */
            }

        }

        return getFieldValidationString( this.classVL, this.otherVL );
    }

    private String getFieldMethodName( String fieldName ) {
        String ms = "get" + fieldName.substring( 0, 1 ).toUpperCase() + fieldName.substring( 1 );

        return ms;
    }

    private String getFieldTypeClassValidation( MetaConstraint mc ) {
        Type t = null;
        String tClass = null;
        if ( mc.getElementType().name().equals( "FIELD" ) ) {
            t = ( (BeanConstraintLocation) mc.getLocation() ).typeOfAnnotatedElement();
        }
        else {
            t = ( (MethodConstraintLocation) mc.getLocation() ).typeOfAnnotatedElement();
        }

        if ( t != null ) {
            if ( t.equals( Integer.class ) || t.equals( Long.class ) || t.equals( Short.class ) || t.equals( Byte.class ) )
                tClass = "digits";
            else if ( t.equals( Float.class ) || t.equals( Double.class ) )
                tClass = "number";
        }

        return tClass;
    }

    /**
     * @param mc
     * @return
     */
    private String getFieldValidation( MetaConstraint mc ) {
        String type = mc.getDescriptor().getAnnotation().annotationType().getName();
        // javax
        if ( type.equals( "javax.validation.constraints.Digits" ) ) {

        }
        if ( type.equals( "javax.validation.constraints.Future" ) ) {

        }
        if ( type.equals( "javax.validation.constraints.Past" ) ) {

        }
        if ( type.equals( "javax.validation.constraints.DecimalMin" ) ) {

        }
        if ( type.equals( "javax.validation.constraints.DecimalMax" ) ) {

        }
        if ( type.equals( "javax.validation.constraints.Size" ) ) {
            Map attrs = mc.getDescriptor().getAttributes();
            Integer min = (Integer) attrs.get( "min" );
            Integer max = (Integer) attrs.get( "max" );
            // this.classVL.add( "min" );
            // this.classVL.add( "max" );
            if ( min != null )
                this.otherVL.add( "minlength=" + "\"" + min + "\"" );
            if ( max != null )
                this.otherVL.add( "maxlength=" + "\"" + max + "\"" );
        }
        if ( type.equals( "javax.validation.constraints.NotNull" ) ) {
            this.classVL.add( "required" );
        }
        if ( type.equals( "javax.validation.constraints.Max" ) ) {
            Map attrs = mc.getDescriptor().getAttributes();
            Long max = (Long) attrs.get( "value" );
           // this.classVL.add( "max" );
            this.otherVL.add( "max=" + "\"" + max + "\"" );
        }
        if ( type.equals( "javax.validation.constraints.Min" ) ) {
            Map attrs = mc.getDescriptor().getAttributes();
            Long min = (Long) attrs.get( "value" );
           // this.classVL.add( "min" );
            this.otherVL.add( "min=" + "\"" + min + "\"" );
        }

        // hibernate
        if ( type.equals( "org.hibernate.validator.constraints.NotBlank" ) ) {
            this.classVL.add( "required" );
        }
        if ( type.equals( "org.hibernate.validator.constraints.NotEmpty" ) ) {
            this.classVL.add( "required" );
        }
        if ( type.equals( "org.hibernate.validator.constraints.CreditCardNumber" ) ) {

            this.classVL.add( "creditcard" );
        }
        if ( type.equals( "org.hibernate.validator.constraints.Email" ) ) {
            this.classVL.add( "email" );
        }
        if ( type.equals( "org.hibernate.validator.constraints.URL" ) ) {
            this.classVL.add( "url" );

        }
        if ( type.equals( "org.hibernate.validator.constraints.Length" ) ) {
            Map attrs = mc.getDescriptor().getAttributes();
            Integer min = (Integer) attrs.get( "min" );
            Integer max = (Integer) attrs.get( "max" );
            if ( min != null )
                this.otherVL.add( "minlength=" + "\"" + min + "\"" );
            if ( max != null )
                this.otherVL.add( "maxlength=" + "\"" + max + "\"" );
        }

        return null;
    }

    private String getFieldOtherValidation( MetaConstraint mc ) {
        /*
         * String type = mc.getDescriptor().getAnnotation().annotationType().getName(); // javax if ( type.equals(
         * "javax.validation.constraints.Max" ) ) { } if ( type.equals( "javax.validation.constraints.Min" ) ) { } //
         * hibernate if ( type.equals( "org.hibernate.validator.constraints.NotEmpty" ) ) { }
         */
        return null;
    }

    private String getFieldValidationString( List cl, List ol ) {
        String cString = "\"";
        for ( Iterator iterator = cl.iterator(); iterator.hasNext(); ) {
            String str = (String) iterator.next();
            cString = cString + " " + str;
        }
        cString = cString + "\"";

        String os = "";
        for ( Iterator iterator = ol.iterator(); iterator.hasNext(); ) {
            String str = (String) iterator.next();
            os = os + " " + str;
        }

        return cString + " " + os;
    }

}
